#pragma once

class BasicObject;

struct DimInfo
{
	U7RECT area;
	U7VECTOR3 worldCoords;
	U7VECTOR3 tileSizes;
	int xleft, xright;
	int yfront, yback;
	int zbot, ztop;
	bool occlude;
	unsigned short shapeType;

	DimInfo( const BasicObject& obj )
	{
		obj.GetShapeRect(&area);
		obj.GetWorldCoords(&worldCoords);
		obj.GetTileSizes(&tileSizes);
		occlude = obj.Occlude();
		shapeType = obj.ShapeID().shapeType;

		// just to check where ztiles is 0
		// chunk (29,37) shape224,7 dust
		assert(tileSizes.x && tileSizes.y && tileSizes.z>=0); 

		xright = worldCoords.x;
		xleft  = xright - tileSizes.x + 1;

		yfront = worldCoords.y;
		yback  = yfront - tileSizes.y + 1;

		zbot = worldCoords.z;
		ztop = zbot + tileSizes.z - 1;
		if ( tileSizes.z == 0 )
			--ztop;
	}

	int Compare( const DimInfo& another ) const
	{
		// return valuse:
		// -1: this < another, draw first
		//  1: this > another, draw later
		//  0: don't care

		// don't care if two objects are not intersected in 2D drawing plane.
		if ( !area.IsIntersected( another.area ) )
			return 0;

		// tapestry is put on the wall so its order is alway bigger than the wall
		// SOLUTION: (occlude)
		//   check occlude flag.

		int xcmp, ycmp, zcmp;
		bool xover, yover, zover;

		CompareRange( xleft, xright, another.xleft, another.xright, xcmp, xover );
		CompareRange( yback, yfront, another.yback, another.yfront, ycmp, yover );
		CompareRange( zbot, ztop, another.zbot, another.ztop, zcmp, zover );

		//
		// check Z axail first, because it's the bird view
		//
		// No Z's overlap
		if ( !zover )
			return zcmp; // the bottom one should be painter first.
		//
		// it seems that checking xover first or checking yover first is an issue.
		// from the visual of the lord british's castle. chunk(56,71), xover first is better
		// but for chunk(97,117), yover first is better.
		//
		else if ( !xover && !yover )
		{
			// the result looks good.
			if ( tileSizes.x > tileSizes.y )
				return ycmp;
			else if ( tileSizes.x < tileSizes.y )
				return xcmp;
			else if ( another.tileSizes.x > another.tileSizes.y )
				return ycmp;
			else if ( another.tileSizes.x < another.tileSizes.y )
				return xcmp;
			else
				return xcmp; // last, just choose xcmp!!!
		}
		// Y's overlap, can't judge by 'ycmp'
		//   B
		//  AB
		//  AB
		//   B
		// No X's overlap, 
		else if (!xover)
			return xcmp; // the left one should be painted first
		// No Y's overlap.
		//  A
		//  A
		//    B
		//    B
		else if (!yover)
			return ycmp; // the back one should be painted first.
		// X's, Y's, Z's overlap
		else
		{
			// completely overlapped
			if ( occlude && !another.occlude )
				return -1;
			if ( !occlude && another.occlude )
				return 1;

			if ( zcmp )
				return zcmp; // the bottom one should be painted first.
			if ( ycmp )
				return ycmp; // the farther one should be painted first.
			// Y is same
			if ( xcmp )
				return xcmp; // the left one should be painted first.

			// xcmp == 0 && ycmp == 0 && zcmp == 0
			// same space
			int w1 = area.Width();
			int h1 = area.Height();
			int w2 = another.area.Width();
			int h2 = another.area.Height();

			// from the order of renderring, the later added object is painted first.
			// so the earlier added object would be painted over the later added object.
			//if ( w1 == h1 && w2 == h2 )
			// chunk(26.18) a lever is under a bucket

			return 0; // don't care
		}

		assert(0); // why here?
		return 0;
	}

private:
	void CompareRange( int from1, int to1, int from2, int to2, int& cmp, bool& overlapped ) const
	{
		// -1: smaller
		//  0: equal
		//  1: bigger
		if ( to1 < from2 ) // [from1,to1]...[from2, to2]
		{
			overlapped = false;
			cmp = -1; // object 1 is smaller
		}
		else if ( to2 < from1 ) // [from2, to2]...[from1, to1]
		{
			overlapped = false;
			cmp = 1; // object 1 is bigger
		}
		else
		{
			overlapped = true;
			// compare the start position, the smaller (left, back or bottom) one should be painted first.
			if ( from1 < from2 ) {      // [from1......to1]
				cmp = -1;               //     [from2......to2]
			}
			else if ( from1 > from2 ) { //     [from1......to1]
				cmp = 1;                // [from2......to2]
			}
			// from1 == from2
			// compare the end position, the shorter one should be painted first.
			else if ( to1 < to2 ) {     // [from1...to1]
				cmp = -1;               // [from2......to2]
			}
			else if ( to1 > to2 ) {     // [from1......to1]
				cmp =  1;               // [from2...to2]
			}
			// from1 == from2, to1 == to2
			// completely overlapped
			else {                      // [from1...to1]
				cmp = 0;                // [from2...to2]
			}
		}
	}

};
